MSMQ
was introduced as part of Windows NT 4.0. It established intermediary
messaging queues that enabled reliability and scalability. An MSMQ
implementation was typically comprised of three major components:
sending application– The sending application prepared the message and placed it into the queue.
message queues (storage)– The message was persisted in the message store.
receiving application–
The receiving application retrieved the message from the queue and
processed it. Alternatively, MSMQ notified an application when a
message was received.
As shown in Figure 1,
the application sending the message and the application receiving the
message were not tightly coupled. If the receiving application was
offline, all messages were persisted. Once the receiving application
was back online, messages were automatically retrieved and processed.
This significantly increased the reliability of messaging-based
applications.
The Queues
Message storage in MSMQ was simply referred to as the “queues.” MSMQ supported two types of queues:
Applications running on different servers throughout the network could find and use public queues via the Active Directory.
The original MSMQ
implementation introduced had a complex programming model and had to be
accessed via a COM interface. .NET later simplified MSMQ by introducing
the System.Messaging namespace, which contained several classes, including Message and MessageQueue. The Message class was used to create and use messages, whereas the MessageQueue class contained functionality to work with and manipulate MSMQ queues.
MSMQ was not installed by
default and had to be enabled on the server. Queues could be created
programmatically or manually using the MMC console. Programmatically,
queues were generated by using the Create() method in the MessageQueue class. The code in the following example could be used to create a private queue on a local machine:
Example 1.
string queuePath = @".\private$\NewQueue"; MessageQueue MessageQ; if (MessageQueue.Exists(queuePath)) MessageQ = new MessageQueue(queuePath); else MessageQ = MessageQueue.Create(queuePath);
|
The Create() method must be provided for the location and name of the queue. In Example 1, the single dot (.) and the keyword Private$ indicates that the queue is being created on the local machine.
The syntax for creating a public queue is:
MachineName\QueueName.
Queues could be deleted via the MMC or by invoking the Delete() method in the MessageQueue class, as shown here:
Example 2.
MessageQueue MessageQ; MessageQ.Delete(".\Private$\NewQueue")
|
Sending and Receiving Messages
The Send method of the MessageQueue class was used by the sending application to post a message to a queue, as follows:
Example 3.
MessageQueue MessageQ; Message Message; MessageQ = new MessageQueue(".\Private$\NewQueue"); Message = new Message("This is a message"); MessageQ.Send(Message);
|
The send method took an object as the first parameter to denote the message body. The argument could be a Message object or any other object. If the object was not of type Message, it was serialized and stored in the message body.
Serializing objects across
process and machine boundaries was not new at the time and had already
been supported by .NET Remoting, DCOM, and Web services. MSMQ, however,
provided the ability to deliver objects asynchronously and reliably so
that they could survive server crashes and reboots. The messages could,
in effect, persist indefinitely until they were retrieved and consumed.
To transfer objects, MSMQ required a formatter to be specified.
Three formatters were provided:
ActiveXMessageFormatter (used to serialize ActiveX objects)
BinaryMessageFormatter (serialized objects using binary serialization)
XMLMessageFormatter (used XML to serialize messages)
The MessageQueue class contained two methods that supported reading a message from a queue:
The Receive method resulted in removing a message from the queue. (The Peek method was similar, but the message was not actually removed.)
Provided here is an example demonstrating the Receive method:
Example 4.
string queuePath = @".\private$\NewQueue"; MessageQueue MessageQ; Message message; MessageQ = new MessageQueue(queuePath); message = MessageQ.Receive;
|
The Receive method would indefinitely block processing. However, the class contained several overloads, one of which took in the TimeSpan argument that allowed an exception to be generated if a message was not returned in a specified time span.
In this example, the TimeSpan has been set to 1 second:
Example 5.
message = MessageQ.Receive(New TimeSpan(1000));
|
The Peek and Receive methods were synchronous in nature and could be invoked asynchronously by using the methods BeginPeek() and EndPeek() or BeginReceive() or EndReceive().